package jef.database.query;

import java.util.List;
import java.util.Map;

import jef.database.Condition;
import jef.database.Condition.Operator;
import jef.database.Field;
import jef.database.IConditionField;
import jef.database.IQueryableEntity;
import jef.database.meta.Reference;

/**
 * 描述最通用的条件容器和查询内容
 * @author Administrator
 * @Date 2011-6-16 
 * @param <T>
 */
public interface Query<T extends IQueryableEntity> extends TypedQuery<T>,JoinElement{
	/**
	 * 添加级联对象过滤条件
	 * 在对象中你可以创建{@link javax.persistence.OneToOne OneToOne} {@link javax.persistence.OneToMany OneToMany}
	 * {@link javax.persistence.ManyToOne ManyToOne}
	 * {@link javax.persistence.ManyToMany ManyToMany}等引用关系。
	 * 查询时这会产生级联查询来加载关联的对象。在这里添加的条件，可被用于过滤<strong>级联的对象</strong>。(注意：是级联引用的指向对象，不是当前对象)<br>
	 * <h3>举例来说：</h3>
	 * <pre><code>
	 *    Student student=new Student();
	 *    student.getQuery().addCondition(QB.eq(Student.Field.id, 1));
	 * 	  student.getQuery().addCascadeCondition( QB.eq(Lesson.Field.name, "语文"));
	 *    Student student=session.load(student);
	 *    //在上例中，无论学生是否有语文课成绩记录，都不影响查询ID=1的学生。
	 *    //然而
	 *    student.getLessons(); //此处得到的Lesson中只会有'语文'
	 *    </code></pre>
	 * 总结来说——CascadeCondition只会影响到级联对象的选择，永远不会影响当前对象的选择。
	 * <br>
	 * 
	 * <h3>为何使用</h3>
	 * 一般来说，仅在一对多的时候使用。在上例中，如果一个学生对应的课程记录有数千条，而我们每次只需要统计学生“语数外”的成绩时，
	 * 将其他课程的成绩查出来显然是十分浪费的。因此我们可以用CascadeCondition进一步缩小一对多查询的选择返回，防止因为一对多关系被滥用造成的性能下降
	 * 
	 * <h3>其他</h3>
	 * 这一特性是即时加载还是延迟加载时都会生效。当用于对一级联时，如果不是左外连接，启用此特性将造成原本一次查出（使用外连接）的结果，被拆成两次查询。
	 * 
	 * 
	 * @param conditions 
	 * @return 当前Query对象
	 * @since 1.1
	 * @author Jiyi
	 */
	Query<T> addCascadeCondition(Condition conditions);

	/**
	 * 添加级联对象过滤条件
	 * 在对象中你可以创建{@link javax.persistence.OneToOne OneToOne} {@link javax.persistence.OneToMany OneToMany}
	 * {@link javax.persistence.ManyToOne ManyToOne}
	 * {@link javax.persistence.ManyToMany ManyToMany}等引用关系。
	 * 查询时这会产生级联查询来加载关联的对象。在这里添加的条件，可被用于过滤<strong>级联的对象</strong>。(注意：是级联引用的指向对象，不是当前对象)<br>
	 * <h3>举例来说：</h3>
	 * <pre><code>
	 *    Student student=new Student();
	 *    student.getQuery().addCondition(QB.eq(Student.Field.id, 1));
	 * 	  student.getQuery().addCascadeCondition( QB.eq(Lesson.Field.name, "语文"));
	 *    Student student=session.load(student);
	 *    //在上例中，无论学生是否有语文课成绩记录，都不影响查询ID=1的学生。
	 *    //然而
	 *    student.getLessons(); //此处得到的Lesson中只会有'语文'
	 *    </code></pre>
	 * 总结来说——CascadeCondition只会影响到级联对象的选择，永远不会影响当前对象的选择。
	 * <br>
	 * 
	 * <h3>为何使用</h3>
	 * 一般来说，仅在一对多的时候使用。在上例中，如果一个学生对应的课程记录有数千条，而我们每次只需要统计学生“语数外”的成绩时，
	 * 将其他课程的成绩查出来显然是十分浪费的。因此我们可以用CascadeCondition进一步缩小一对多查询的选择返回，防止因为一对多关系被滥用造成的性能下降
	 * 
	 * <h3>其他</h3>
	 * 这一特性是即时加载还是延迟加载时都会生效。当用于对一级联时，如果不是左外连接，启用此特性将造成原本一次查出（使用外连接）的结果，被拆成两次查询。
	 * @param refName 发生关系的字段名, 比如A -> B有多条路径的引用关系。用这个名称可以区分出是哪一条引用关系，可以指定间接级联关系，如 member.info
	 * @param conditions
	 * @return 当前Query对象
	 * @since 1.1
	 * @author Jiyi
	 */
	Query<T> addCascadeCondition(String refName,Condition... conditions);
	
	
	/**
	 * 添加扩展查询
	 * @param querys
	 * @return 当前Query对象
	 */
	Query<T> addExtendQuery(Query<?> querys);
	
	/**
	 * 清除所有其他条件，设置为全纪录查询条件
	 * @return 当前Query对象
	 */
	Query<T> setAllRecordsCondition();
	
	/**
	 * 添加一个条件,运算符为equals
	 * @param field
	 * @param value
	 * @return 当前Query对象
	 */
	Query<T> addCondition(Field field,Object value);
	
	/**
	 * 添加一个条件
	 * @param field 字段
	 * @param oper 运算符
	 * @param value 值
	 * @return 当前Query对象
	 */
	Query<T> addCondition(Field field, Operator oper,Object value);
	
	/**
	 * 添加一个条件，如Or Not And Exists NotExists等复杂条件
	 * @param condition 条件
	 * @return 当前Query对象
	 * @see IConditionField
	 * @see IConditionField.And
	 * @see IConditionField.Or
	 * @see IConditionField.Not
	 * @see IConditionField.Exists
	 * @see IConditionField.NotExists
	 * @since 1.1
	 * @author Jiyi
	 * @see IConditionField
	 */
	Query<T> addCondition(IConditionField condition);
	
	/**
	 * 添加一个条件，与之前的条件为And关系
	 * @param condition 条件
	 * @return Query对象本身
	 */
	Query<T> addCondition(Condition condition);
	
	/**
	 * 得到子查询过滤条件
	 * @return 所有的子查询过滤条件
	 */
	Map<Reference, List<Condition>> getFilterCondition();
	
	/**
	 * 目前的设计趋势是逐步将DataObject相分离，用IQuery来代替原来DataObject的查询接口。
	 * @return
	 */
	T getInstance();
	
	/**
	 * 得到Query的其他查询提供者, 
	 * @return 其他外连接查询
	 */
	Query<?>[] getOtherQueryProvider();
	
	/**
	 * 设置自定义的查询表名
	 * @param name
	 */
	void setCustomTableName(String name);
	
	/**
	 * 获取：是否尝试用外连接的方式，一次性查出级联关系
	 * 
	 * @return 如果开启自动外连接功能，返回true
	 * @see jef.database.DbCfg#DB_USE_OUTER_JOIN
	 */
	public boolean isCascadeViaOuterJoin();

	/**
	 * 设置：是否尝试用外连接的方式，一次性查出级联关系
	 * @param cascadeViaOuterJoin 如果为true，将尽量合并数据库查询来减少操作次数。
	 */
	public void setCascadeViaOuterJoin(boolean cascadeViaOuterJoin);
	
	/**
	 * 设置是否要使用级联查询。调用这个方法的效果等同于同时调用下面两个方法<code><pre>
	 * .getResultTransformer().setLoadVsMany(false);
	 * .getResultTransformer().setLoadVsOne(false);
	 * </pre></code>
	 * @param cascade 是否要级联查询
	 * @see jef.database.wrapper.populator.Transformer#setLoadVsMany(boolean)
	 * @see jef.database.wrapper.populator.Transformer#setLoadVsOne(boolean)
	 */
	public void setCascade(boolean cascade);
	

	/**
	 * 是否查询全部记录
	 * @return
	 */
	boolean isAll();

	/**
	 * 查询条件生成器
	 * <strong>试验性功能。<strong>
	 * @return Terms
	 * @see Terms
	 */
	Terms terms();
}
